/* @formatter:off
 * Copyright (c) 2011 Lucas <lucas03093@gmail.com>
 * 
 * 
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
/* @formatter:on */

package nu.korkad.daytracker.activity;

import java.io.File;

import nu.korkad.daytracker.R;
import nu.korkad.daytracker.alertdialog.About;
import nu.korkad.daytracker.database.DataHelper;
import nu.korkad.daytracker.info.AppInfo;
import nu.korkad.daytracker.info.Network;
import nu.korkad.daytracker.io.IO;
import nu.korkad.daytracker.io.Log;
import nu.korkad.daytracker.settings.Config;
import nu.korkad.daytracker.settings.PrefStore;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.format.DateFormat;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.bugsense.trace.BugSenseHandler;
import com.dropbox.client2.DropboxAPI;
import com.dropbox.client2.android.AndroidAuthSession;
import com.dropbox.client2.session.AppKeyPair;

public class Main extends Activity
{
    public EditText    main_input;
    public TextView    main_info_company;
    public TextView    main_info_checkin;
    public TextView    main_info_checkout;
    public TextView    main_notification_save;
    public TextView    main_notification_checkin;
    public TextView    main_notification_checkout;
    public Button      main_button_checkin;
    public Button      main_button_checkout;
    public Button      main_button_save;
    public Button      main_button_archive;
    private int        currentId;
    private String     companyName;
    private DataHelper dh;
    private boolean    crashReport        = false;
    public boolean     saveInProgress     = false;
    public boolean     checkinInProgress  = false;
    public boolean     checkoutInProgress = false;
    
    @Override
    protected void onPause()
    {
        super.onPause();
        
        // Save text
        if (dh != null)
            saveText();
        
        // Close dh
        if (dh != null)
        {
            dh.close();
            dh = null;
        }
    }
    
    @Override
    protected void onResume()
    {
        super.onResume();
        
        // Open dh
        if (dh == null)
            dh = new DataHelper(this);
        
        // Set company name if available
        if (Settings.companyName != null)
        {
            companyName = Settings.companyName;
            main_info_company.setText(getString(R.string.layout_main_info_company) + " " + companyName);
            PrefStore.setCompanyName(this, companyName);
            dh.updateCompanyName(companyName, currentId);
            
            // Don't waste memory
            Settings.companyName = null;
        }
        
        // Set device id if available
        if (Settings.deviceId != null && !Settings.deviceId.equals(""))
        {
            Config.DROPBOX_DEVICE_ID = Settings.deviceId;
            PrefStore.setDeviceId(this, Settings.deviceId);
            
            // Don't waste memory
            Settings.deviceId = null;
        }
        else if (Settings.deviceId != null && Settings.deviceId.equals(""))
        {
            String id = AppInfo.generateDeviceId(this);
            Config.DROPBOX_DEVICE_ID = id;
            PrefStore.setDeviceId(this, id);
            
            // Don't waste memory
            Settings.deviceId = null;
            id = null;
        }
        
        // Check if they changed crash reporting
        if (PrefStore.getCrashReport(this) != crashReport && PrefStore.getCrashReport(this) == true)
        {
            BugSenseHandler.setup(this, Config.APPLICATION_BUGSENSE);
            crashReport = PrefStore.getCrashReport(this);
        }
    }
    
    /** Called when the activity is first created. */
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        
        // Set layout
        setContentView(R.layout.activity_main);
        
        // Save crash report setting
        crashReport = PrefStore.getCrashReport(this);
        
        // Crash report
        if (crashReport)
            BugSenseHandler.setup(this, Config.APPLICATION_BUGSENSE);
        
        // Get datahelper
        dh = new DataHelper(this);
        
        // Set stuff
        currentId = PrefStore.getCurrentId(this);
        companyName = PrefStore.getCompanyName(this);
        
        // Transfer old settings if necessary
        if (currentId == 0 && PrefStore.getOldCurrentId(this) != 0)
        {
            // Current id 
            currentId = PrefStore.getCurrentId(this);
            PrefStore.setCurrentId(this, currentId);
            
            // Company name
            companyName = PrefStore.getOldCompanyName(this);
            PrefStore.setCompanyName(this, companyName);
            
            // Database version
            PrefStore.setDatabaseVersion(this, PrefStore.getOldDatabaseVersion(this));
            
            // Delete sharedprefs xml file
            new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    File f1 = new File(Config.INTERNAL_DIR_SHAREDPREF + File.separator + Config.PREFSTORE_PRIVATE + ".xml");
                    f1.delete();
                }
            }).start();
        }
        
        // Generate device id if needed
        if (PrefStore.getDeviceId(this).equals(""))
            PrefStore.setDeviceId(this, AppInfo.generateDeviceId(this));
        
        // Set it in config
        if (Config.DROPBOX_DEVICE_ID.equals(""))
            Config.DROPBOX_DEVICE_ID = PrefStore.getDeviceId(this);
        
        // Update current id if necessary
        updateCurrentId(false);
        
        // Get UI stuff
        main_input = (EditText) findViewById(R.id.layout_main_input_dayinfo);
        main_info_company = (TextView) findViewById(R.id.layout_main_text_info_company);
        main_info_checkin = (TextView) findViewById(R.id.layout_main_text_info_checkin);
        main_info_checkout = (TextView) findViewById(R.id.layout_main_text_info_checkout);
        main_notification_save = (TextView) findViewById(R.id.layout_main_text_notification_save);
        main_notification_checkin = (TextView) findViewById(R.id.layout_main_text_notification_checkin);
        main_notification_checkout = (TextView) findViewById(R.id.layout_main_text_notification_checkout);
        main_button_checkin = (Button) findViewById(R.id.layout_main_button_checkin);
        main_button_checkout = (Button) findViewById(R.id.layout_main_button_checkout);
        main_button_save = (Button) findViewById(R.id.layout_main_button_save);
        main_button_archive = (Button) findViewById(R.id.layout_main_button_newday);
        
        // Check company name
        if (companyName.equals(""))
            main_info_company.setText(getString(R.string.layout_main_info_company) + " "
                    + getString(R.string.layout_main_info_company_none));
        else
            main_info_company.setText(getString(R.string.layout_main_info_company) + " " + companyName);
        
        // Set UI stuff
        main_input.setText(getText());
        updateCheckInOut();
    }
    
    /**
     * Updates "Check in" and "Check out" TextViews with dateformat.
     */
    public void updateCheckInOut()
    {
        // Get data
        String[] data = dh.getInfo(currentId);
        
        // Check in and out
        String checkin = "";
        String checkout = "";
        long checkin_time = Long.parseLong(data[1]) * 1000;
        long checkout_time = Long.parseLong(data[2]) * 1000;
        
        // Get timestamp so humans can read it
        if (Long.parseLong(data[1]) == 0)
            checkin = getString(R.string.layout_main_info_checkin_never);
        else
            checkin = DateFormat.getTimeFormat(this).format(checkin_time) + " " + DateFormat.getMediumDateFormat(this).format(checkin_time);
        if (Long.parseLong(data[2]) == 0)
            checkout = getString(R.string.layout_main_info_checkout_never);
        else
            checkout = DateFormat.getTimeFormat(this).format(checkout_time) + " "
                    + DateFormat.getMediumDateFormat(this).format(checkout_time);
        
        // Set text
        main_info_checkin.setText(getString(R.string.layout_main_info_checkin) + " " + checkin);
        main_info_checkout.setText(getString(R.string.layout_main_info_checkout) + " " + checkout);
    }
    
    /**
     * Checks in.
     * 
     * @param v
     */
    public void onClickCheckIn(View v)
    {
        new run().execute("checkin");
    }
    
    /**
     * Checks out.
     * 
     * @param v
     */
    public void onClickCheckOut(View v)
    {
        new run().execute("checkout");
    }
    
    /**
     * Saves the text.
     * 
     * @param v
     */
    public void onClickSaveText(View v)
    {
        new run().execute("savetext", main_input.getText().toString());
    }
    
    /**
     * Starts a new day.
     * 
     * @param v
     */
    // TODO: Move toast to textview
    public void onClickNewDay(View v)
    {
        // Save text
        saveText();
        
        // Update current id
        updateCurrentId(true);
        
        // Update the input fields
        main_input.setText("");
        updateCheckInOut();
        
        // Notify user
        Toast.makeText(this, getString(R.string.toast_button_newday), Toast.LENGTH_SHORT).show();
    }
    
    /**
     * Saves the text and notifies the user if necessary.
     */
    public void saveText()
    {
        // Save the text
        dh.updateText(main_input.getText().toString(), currentId);
        
        // Export report
        if (!PrefStore.getDropboxKey(getBaseContext()).equals("") && PrefStore.getAutoExport(getBaseContext())
                && Network.networkCheck(getBaseContext()).equals("ok"))
        {
            // Get dropbox stuff
            AppKeyPair appKeys = new AppKeyPair(Config.DROPBOX_APP_KEY, Config.DROPBOX_APP_SECRET);
            AndroidAuthSession session = new AndroidAuthSession(appKeys, Config.DROPBOX_ACCESS_TYPE);
            DropboxAPI<AndroidAuthSession> mDBApi = new DropboxAPI<AndroidAuthSession>(session);
            
            // Export to dropbox
            IO.exportReportToDropbox(currentId, dh, getBaseContext(), mDBApi);
        }
    }
    
    /**
     * Gets the text from the database.
     * 
     * @return String
     */
    public String getText()
    {
        // Get data
        String[] data = dh.getInfo(currentId);
        
        // Return it
        return data[3];
    }
    
    /**
     * Switches to a new row in the database. (e.g changing to a new day)
     * 
     * @param force
     *            boolean
     */
    public void updateCurrentId(boolean force)
    {
        // Resets current id
        // Needed for archive activity to show correct number of rows.
        if (PrefStore.getDatabaseVersion(this) != Config.DATABASE_VERSION)
        {
            currentId = (int) dh.insert(companyName, 0, 0, "", 1);
            PrefStore.setCurrentId(this, currentId);
            PrefStore.setDatabaseVersion(this, Config.DATABASE_VERSION);
        }
        else if (currentId == 0 || force)
        {
            currentId = (int) dh.insert(companyName, 0, 0, "", 1);
            PrefStore.setCurrentId(this, currentId);
        }
    }
    
    /**
     * Formats date and time to human readable.
     * 
     * @param time
     *            long
     * @return String
     */
    public String formatTime(long time)
    {
        return DateFormat.getTimeFormat(this).format(time) + " " + DateFormat.getMediumDateFormat(this).format(time);
    }
    
    /** Creates the options menu */
    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        MenuInflater inflater = getMenuInflater();
        
        // Set menu layout
        inflater.inflate(R.menu.main, menu);
        
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        switch (item.getItemId())
        {
            case R.id.menu_main_archive:
                startActivity(new Intent(this, Archive.class));
                break;
            
            case R.id.menu_main_about:
                AlertDialog builder = About.create(this, getString(R.string.dialog_about_text_about),
                        getString(R.string.dialog_about_button_ok));
                builder.show();
                break;
            
            case R.id.menu_main_saveexit:
                finish();
                break;
            
            case R.id.menu_main_settings:
                startActivity(new Intent(this, Settings.class));
                break;
            
            case R.id.menu_main_export_external:
                // Start new thread
                new Export().execute("external");
                break;
            
            case R.id.menu_main_export_dropbox:
                // Check network availability
                if (!Network.networkCheck(this).equals("ok"))
                    Toast.makeText(this, Network.networkCheck(this), Toast.LENGTH_LONG).show();
                else if (PrefStore.getDropboxKey(this).equals("")) // Check if user is authenticated against dropbox
                    Toast.makeText(this, getString(R.string.toast_dropbox_credentials), Toast.LENGTH_SHORT).show();
                else
                    // Export files to dropbox
                    new Export().execute("dropbox");
                break;
            
            case R.id.menu_main_import_external:
                // Start new thread
                new Import().execute("external");
                break;
            
            default:
                return super.onOptionsItemSelected(item);
        }
        
        return true;
    }
    
    private class Export extends AsyncTask<String, Void, String>
    {
        
        @Override
        protected void onPreExecute()
        {
            // Close db
            if (dh != null)
            {
                dh.close();
                dh = null;
            }
            
            // Disable UI elements
            main_input.setEnabled(false);
            main_button_checkin.setEnabled(false);
            main_button_checkout.setEnabled(false);
            main_button_save.setEnabled(false);
            main_button_archive.setEnabled(false);
            
            // Tell the user we're exporting data
            Toast.makeText(getBaseContext(), getString(R.string.toast_export_inprogress), Toast.LENGTH_SHORT).show();
        }
        
        @Override
        protected String doInBackground(String... type)
        {
            if (type[0].equals("external"))
                return IO.toExternal();
            else if (type[0].equals("dropbox"))
                return IO.toDropbox(getBaseContext());
            
            return "";
        }
        
        @Override
        protected void onPostExecute(String result)
        {
            // Open db conn
            dh = new DataHelper(getBaseContext());
            
            // Enable UI elements
            main_input.setEnabled(true);
            main_button_checkin.setEnabled(true);
            main_button_checkout.setEnabled(true);
            main_button_save.setEnabled(true);
            main_button_archive.setEnabled(true);
            
            // Tell the user we're done
            if (result.equals("external"))
                Toast.makeText(getBaseContext(), getString(R.string.toast_export_tosd_ok), Toast.LENGTH_SHORT).show();
            else if (result.equals("dropbox"))
                Toast.makeText(getBaseContext(), getString(R.string.toast_export_todropbox_ok), Toast.LENGTH_SHORT).show();
            else
            {
                Toast.makeText(getBaseContext(), result, Toast.LENGTH_LONG).show();
                Log.toExternal(result);
            }
        }
    }
    
    private class Import extends AsyncTask<String, Void, String>
    {
        @Override
        protected void onPreExecute()
        {
            // Close db
            if (dh != null)
            {
                dh.close();
                dh = null;
            }
            
            // Disable UI elements
            main_input.setEnabled(false);
            main_button_checkin.setEnabled(false);
            main_button_checkout.setEnabled(false);
            main_button_save.setEnabled(false);
            main_button_archive.setEnabled(false);
            
            // Tell the user we're importing data
            Toast.makeText(getBaseContext(), getString(R.string.toast_import_inprogress), Toast.LENGTH_SHORT).show();
        }
        
        @Override
        protected String doInBackground(String... type)
        {
            if (type[0].equals("external"))
                return IO.fromExternal();
            
            return "";
        }
        
        @Override
        protected void onPostExecute(String result)
        {
            // Open db conn
            dh = new DataHelper(getBaseContext());
            
            // Update UI elements
            main_input.setText(getText());
            updateCheckInOut();
            currentId = PrefStore.getCurrentId(getBaseContext());
            
            // Enable UI elements
            main_input.setEnabled(true);
            main_button_checkin.setEnabled(true);
            main_button_checkout.setEnabled(true);
            main_button_save.setEnabled(true);
            main_button_archive.setEnabled(true);
            
            // Tell the user we're done
            if (result.equals("external"))
                Toast.makeText(getBaseContext(), getString(R.string.toast_import_external_ok), Toast.LENGTH_SHORT).show();
            else
            {
                Toast.makeText(getBaseContext(), result, Toast.LENGTH_LONG).show();
                Log.toExternal(result);
            }
        }
    }
    
    private class run extends AsyncTask<String, String, String>
    {
        @Override
        protected String doInBackground(String... data)
        {
            // Get current time
            long time = System.currentTimeMillis();
            String formatTime = formatTime(time);
            int inttime = (int) (time / 1000);
            
            // Check what to do
            if (data[0].equals("checkin"))
            {
                // Update UI
                publishProgress("1", formatTime);
                
                // Save time to db
                dh.updateCheckIn(inttime, currentId);
            }
            else if (data[0].equals("checkout"))
            {
                // Update UI
                publishProgress("2", formatTime);
                
                // Save time to db
                dh.updateCheckOut(inttime, currentId);
            }
            else if (data[0].equals("savetext"))
            {
                // Update UI
                publishProgress("3");
                
                // Save text to db
                dh.updateText(data[1], currentId);
                
                if (!PrefStore.getDropboxKey(getBaseContext()).equals("") && PrefStore.getAutoExport(getBaseContext())
                        && Network.networkCheck(getBaseContext()).equals("ok"))
                {
                    // Get dropbox stuff
                    AppKeyPair appKeys = new AppKeyPair(Config.DROPBOX_APP_KEY, Config.DROPBOX_APP_SECRET);
                    AndroidAuthSession session = new AndroidAuthSession(appKeys, Config.DROPBOX_ACCESS_TYPE);
                    DropboxAPI<AndroidAuthSession> mDBApi = new DropboxAPI<AndroidAuthSession>(session);
                    
                    // Export to dropbox
                    IO.exportReportToDropbox(currentId, dh, getBaseContext(), mDBApi);
                }
            }
            
            // Wait 2 seconds before continueing
            try
            {
                Thread.sleep(2000);
            }
            catch (InterruptedException e)
            {
            }
            
            // Update UI
            return data[0];
        }
        
        @Override
        protected void onProgressUpdate(String... data)
        {
            switch (Integer.parseInt(data[0].trim()))
            {
                case 1:
                    // Tell the user we're saving the data
                    if (checkinInProgress == false)
                    {
                        main_notification_checkin.setVisibility(View.VISIBLE);
                        checkinInProgress = true;
                    }
                    
                    // Update checkin text
                    main_info_checkin.setText(getString(R.string.layout_main_info_checkin) + " " + data[1]);
                    break;
                case 2:
                    // Tell the user we're saving the data
                    if (checkoutInProgress == false)
                    {
                        main_notification_checkout.setVisibility(View.VISIBLE);
                        checkoutInProgress = true;
                    }
                    
                    // Update checkout text
                    main_info_checkout.setText(getString(R.string.layout_main_info_checkout) + " " + data[1]);
                    break;
                case 3:
                    // Tell the user we're saving the data
                    if (saveInProgress == false)
                    {
                        main_notification_save.setVisibility(View.VISIBLE);
                        saveInProgress = true;
                    }
                    break;
            }
        }
        
        @Override
        protected void onPostExecute(String result)
        {
            if (result.equals("checkin") && checkinInProgress == true)
            {
                main_notification_checkin.setVisibility(View.INVISIBLE);
                checkinInProgress = false;
            }
            else if (result.equals("checkout") && checkoutInProgress == true)
            {
                main_notification_checkout.setVisibility(View.INVISIBLE);
                checkoutInProgress = false;
            }
            else if (result.equals("savetext") && saveInProgress == true)
            {
                main_notification_save.setVisibility(View.INVISIBLE);
                saveInProgress = false;
            }
        }
    }
}